package de.unikoblenz.west.csxpoi.server;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * Encapsulates a cluster of POIs for the DBSCAN clustering algorithm and
 * defines the static clusters NOISE and NONE. Members can be added and deleted
 * and the medoid of the cluster can be determined.
 */
public class Cluster implements Iterable<PoiWrapper> {

	public static final Cluster NOISE = new Cluster();
	public static final Cluster NONE = new Cluster();

	private Set<PoiWrapper> mMembers = new HashSet<PoiWrapper>();

	/**
	 * Get the members of the cluster.
	 * 
	 * @return the set of members of the cluster
	 */
	public Set<PoiWrapper> getMembers() {
		return mMembers;
	}

	/**
	 * Adds a member to the cluster.
	 * 
	 * @param poi
	 *            the member to add
	 */
	public void addMember(PoiWrapper poi) {
		mMembers.add(poi);
	}

	/**
	 * Removes a member from the cluster.
	 * 
	 * @param poi
	 *            the member to remove
	 * @return true if poi was a member of the cluster
	 */
	public boolean removeMember(PoiWrapper poi) {
		return mMembers.remove(poi);
	}

	/**
	 * Returns the iterator for the members of the cluster.
	 */
	public Iterator<PoiWrapper> iterator() {
		return mMembers.iterator();
	}

	/**
	 * Determines the medoid of the cluster, which is the member with the
	 * maximum average similarity to all others.
	 * 
	 * @return the medoid of the cluster
	 * @throws SimilarityException
	 */
	public PoiWrapper getMedoid(Similarity similarity) throws SimilarityException {

		PoiWrapper medoid = null;
		double maximumSimilarity = 0;
		

		for (PoiWrapper base : mMembers) {

			double averageSimilarity = 0;

			for (PoiWrapper target : mMembers) {
				if (!target.equals(base)) {
					averageSimilarity += similarity.similarity(target, base);
				}
			}

			averageSimilarity /= (mMembers.size() - 1);
			if (averageSimilarity > maximumSimilarity) {
				maximumSimilarity = averageSimilarity;
				medoid = base;
			}
		}
		return medoid;
	}

}
